#!/usr/bin/env python
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, PropertyLoader
from sqlalchemy.schema import Table, MetaData, Column
from sqlalchemy.ext.declarative import declarative_base
from renyare.log import logger


class Database:
	"""
	Empty middleware - analog of site virtual directory
	"""
	log = logger()
	def __init__(self, app, **kw):
		self.orig_app = app
		self.config = kw.get('config') or []

	def __call__(self, environ, start_response):
		prefix =  environ['renyare.config']['options']['DB_PREFIX']
		encoding = environ['renyare.config']['options']['DB_ENCODING']
		engine = create_engine( environ['renyare.config']['options']['DB_CONNECTION_STRING'], encoding=encoding)
		engine.connect()
		Session = scoped_session(sessionmaker(transactional=True, autoflush=False, bind=engine))
		metadata = MetaData(bind=engine)
		if(self.log.root.level == 0):
			# Remove console logging and replace it with logging to debugging stream
			engine.logger = log
			engine.echo = True
		environ['renyare.db'] = DbData(Session, prefix, engine, metadata)
		return self.orig_app(environ, start_response)

class DbData:
	log = logger()
	_new_class = "_Renyare"
	def __init__(self, session, prefix, engine, metadata):
		self.session = session
		self.engine = engine
		self.prefix = prefix
		self.metadata = metadata
		self._classes = {}
		self.Base = declarative_base(self.engine, self.metadata)

	def new(self, class_):
		new_name = self._new_class + class_.__name__
		if(new_name in self._classes):
			return self._classes[new_name]
		# Add the prefix to tablename
		class_.__tablename__ = self.prefix + class_.__tablename__
		for key,value in class_.__dict__.iteritems():
			if isinstance(value, PropertyLoader) and not isinstance(value.argument, basestring):
				name = value.argument.__name__
				if not name in self._classes:
					value.argument = self.new(value.argument)
				value.argument = value.argument.__name__
				if isinstance(value.secondary, basestring):
					value.secondary = Table(self.prefix + value.secondary, self.metadata, autoload=True, useexisting=True)
		if class_.__tablename__ in self.metadata.tables:
			self.log.debug(dir(self.metadata))
			self.metadata.remove(self.metadata.tables[class_.__tablename__])
		RealClass = type(new_name, ( self.Base, ), class_.__dict__)
		self._classes[new_name] = RealClass
		return RealClass

	def create_table(self, class_):
		metadata = MetaData(bind=self.engine)
		table = Table(self.prefix + class_.__tablename__, self.metadata, useexisting=True)
		new_tables = []
		if '__related__' in class_.__dict__:
			for c in class_.__related__:
				if not self.prefix + c.__tablename__ in self.metadata.tables:
					 new_tables.append(Table(self.prefix + c.__tablename__, self.metadata, autoload=True))
		self.log.debug(self.metadata.tables.keys())
		for key,value in class_.__dict__.iteritems():
			if isinstance(value, Column):
				self.log.debug(dir(value))
				self.log.debug("FK:"+str(value.foreign_keys))
				#newcol = value.copy()
				#newcol.foreign_keys = value.foreign_keys
				table.append_column(value)
		table.create(checkfirst=True)
		return table
